//
//  ZYPopLayerManager.m
//  DesignMode
//
//  Created by wangzhipan on 2024/11/18.
//

#import "ZYPopLayerManager.h"
#import "ZYPopLayerRule.h"
#import "ZYPopTimerRequest.h"

typedef NS_ENUM(NSInteger, WillShowRequestType) {
    WillShowRequestTypeNone = 0,
    WillShowRequestTypeFource,
    WillShowRequestTypeInterrupt,
    WillShowRequestTypeQueue
};

@interface ZYPopLayerManager()
@property (nonatomic, strong, nullable) NSMutableArray <id<IPopLayerRequest>>*waitQueue;
@property (nonatomic, strong, nullable)  id<IPopLayerRequest>fourceRequest;
@property (nonatomic, strong, nullable) NSMutableArray <ZYPopLayerRule *>*ruleList;
@property (nonatomic, strong, nullable) NSMutableArray<id<IPopLayerRequest>> *disPlayList;
@property (nonatomic, strong, nullable) id<IPopLayerRequest> interruptRequest;
@end

@implementation ZYPopLayerManager
+ (instancetype)sharedInstance
{
    static id _instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}
- (instancetype)init
{
    if (self = [super init]) {
        self.waitQueue = [NSMutableArray arrayWithCapacity:5];
        self.ruleList = [NSMutableArray arrayWithCapacity:5];
        self.disPlayList = [NSMutableArray arrayWithCapacity:5];
    }
    return self;
}
- (void)addRequest:(nonnull id<IPopLayerRequest>)request
{
    NSAssert([NSThread isMainThread], @"PopLayer: addRequest must in mainThread");
    if (!request) {
        return;
    }
    ZYPopLayerRule *rule = [self findRuleOfPopLayerId:request.popLayerId];
    //手动触发以及基础避让的引导层，直接展示， 并且结束展示由外部控制
    if (rule.isBasic || request.isManual) {
        NSLog(@"PopLayer: 【%@】 showing, it isManual or isBasic", request.popLayerId);
        [self.disPlayList addObject:request];
        [self p_configFinishBlockForDisplayRequest:request];
        [request doShow];
        return;
    }
    
    [self p_addToQueueIfNeed:request rule:rule];
    [self p_showIfNeed];
}

- (void)removeRequest:(nonnull id<IPopLayerRequest>)request
{
    NSAssert([NSThread isMainThread], @"PopLayer: removeRequest must in mainThread");
    
    if (!request) {
        return;
    }
    
    NSLog(@"PopLayer: request【%@】 did remove", request.popLayerId);
    
    //先判断是否是fourceRequest 或者 interruptRequest
    if (request == self.fourceRequest) {
        [request doClose:YES];
        self.fourceRequest = nil;
    }
    else if (request == self.interruptRequest) {
        [request doClose:NO];
        self.interruptRequest = nil;
    }
    else if ([self.disPlayList containsObject:request]) {
        [request doClose:NO];
    }
    else if ([self.waitQueue containsObject:request]) {
        [request doClose:YES];
    }
    else {
        NSLog(@"PopLayer: no this PopLayer【%@】", request.popLayerId);
    }
}

- (ZYPopLayerRule *)findRuleOfPopLayerId:(NSString *)popLayerId
{
    ZYPopLayerRule *rule = nil;
    if (popLayerId.length && [ZYPopLayerRule isExistRule:popLayerId]) {
        for (ZYPopLayerRule *obj in self.ruleList) {
            if ([obj.popLayerId isEqualToString:popLayerId]) {
                return obj;
            }
        }
        rule = [[ZYPopLayerRule alloc] initWithPopLayerId:popLayerId];
        [self.ruleList addObject:rule];
    }
    return rule;
}
#pragma mark -- private


- (void)p_addToQueueIfNeed:(id<IPopLayerRequest>)request rule:(ZYPopLayerRule *)rule
{
    /*
     加入逻辑：
     1、先检查是否可以显示，不能显示直接丢弃该request
     2、检查是否强制展示：
        是则放入fourceRequest，如果fourceRequest有值则直接丢弃 该request
     
     3、否则判断是否能排队：
            是则加入waitQueue，按优先级排序以及淘汰
     4、否则判断当前是否有正在展示、中断展示、强制展示 的引导：
                是则直接丢弃
                
     5、否则加入waitQueue队列，触发展示逻辑
     */
    if (![rule enableShow]) {
        NSLog(@"PopLayer: 【%@】 can not show", request.popLayerId);
        [request doClose:YES];
        return;
    }
    
    if (rule.isFourceShow && self.fourceRequest) {
        NSLog(@"PopLayer: 【%@】 can not show, because it is FourceRequest but old fourceRequest no nil, no nil PopLayer:【%@】", request.popLayerId, self.fourceRequest.popLayerId);
        [request doClose:YES];
        return;
    }
    else if (rule.isFourceShow)
    {
        self.fourceRequest = request;
    }
    else if (rule.isToQueue || self.waitQueue.count == 0)
    {
        [self p_addRequestToWaitQueue:request];
    }
}

- (void)p_addRequestToWaitQueue:(id<IPopLayerRequest>)request
{
    if (self.waitQueue.count == 0) {
        [self.waitQueue addObject:request];
        return;
    }
    
    NSUInteger insertIndex = 0;
    for (id<IPopLayerRequest> obj in self.waitQueue) {
        if (obj.priority <= request.priority) {
            break;
        }
        insertIndex++;
    }
    [self.waitQueue insertObject:request atIndex:insertIndex];
    if (self.waitQueue.count > 2) {
        id<IPopLayerRequest>lastRequest = [self.waitQueue lastObject];
        NSLog(@"PopLayer: 【%@】 can not show, because it priority lower, new Request priority heighter, new PopLayer:【%@】", lastRequest.popLayerId, request.popLayerId);
        [lastRequest doClose:YES];
        [self.waitQueue removeLastObject];
    }
}

- (void)p_showIfNeed
{
    /*
     展示逻辑：
     
     1、首先询问fourceRequest是否有强制展示引导：
                是则判断当前是否有正在展示的引导disPlayList：
                    否：直接展示
                    是：判断当前正在展示的引导是否 > 1 或者 当前正在展示的引导是否是强制展示\手动展示：
                        是强制展示则不展示
                        是手动触发展示则直接盖在上面
                        否则判断当前正在展示的引导是否可以打断恢复：
                            否则移除当前引导，展示新引导
                            是则打断引导的展示，放入interruptRequest中，等待新引导展示完再恢复interruptRequest的展示
     
     2、询问interruptRequest 是否存在：
                是：当前无正在展示的引导，则立马恢复
                    当前有则继续等待正在展示的引导cancel
     
     3、interruptRequest不存在：
                询问waitQueue中是否存在引导层
                    是：则取出队列第一个引导展示
                    否：结束询问
     */
    
    if (self.disPlayList.count > 1 || [self findRuleOfPopLayerId:self.disPlayList.firstObject.popLayerId].isFourceShow) {
        NSLog(@"PopLayer: showIfNeed but notShow: %lu  %d", (unsigned long)self.disPlayList.count, [self findRuleOfPopLayerId:self.disPlayList.firstObject.popLayerId].isFourceShow);
        return;
    }
    
    id<IPopLayerRequest>showRequest = nil;
    WillShowRequestType type = WillShowRequestTypeNone;
    if (self.fourceRequest) {
        BOOL enableShow = self.disPlayList.count <= 1;
        showRequest = enableShow ? self.fourceRequest : nil;
        type = enableShow ? WillShowRequestTypeFource : type;
    }
    else if (self.interruptRequest && self.disPlayList.count == 0) {
        showRequest = self.interruptRequest;
        self.interruptRequest = nil;
        type = WillShowRequestTypeInterrupt;
    }
    else if (self.waitQueue.count && self.disPlayList.count == 0) {
        showRequest = [self.waitQueue firstObject];
        [self.waitQueue removeObject:showRequest];
        type = WillShowRequestTypeQueue;
    }
    
    BOOL isAddToDisplay = false;
    if (type == WillShowRequestTypeFource) {
        id<IPopLayerRequest>displayRequest = self.disPlayList.firstObject;
        ZYPopLayerRule *displayRule = [self findRuleOfPopLayerId:displayRequest.popLayerId];
        //当前正在展示的引导层是否可以打断恢复
        if (displayRequest && [self p_canResume:displayRequest]) {
            NSLog(@"PopLayer: new interruptRequest interrupting【%@】", displayRequest.popLayerId);
            [displayRequest doInterrupt];
            [self.interruptRequest doClose:NO];
            NSLog(@"PopLayer: remove old interruptRequest【%@】 beacause new interruptRequest【%@】", self.interruptRequest.popLayerId, displayRequest.popLayerId);
            //有多个打断恢复的引导，只保留最新的，旧的移除
            self.interruptRequest = displayRequest;
        }
        else if (!displayRequest.isManual) {
            [displayRequest doClose:NO];
            NSLog(@"PopLayer: remove request【%@】, because fourceRequest【%@】", displayRequest.popLayerId, showRequest.popLayerId);
        }
        [showRequest doShow];
        isAddToDisplay = true;
    }
    else if (type == WillShowRequestTypeInterrupt) {
        [showRequest doResume];
        isAddToDisplay = true;
    }
    else if (type == WillShowRequestTypeQueue) {
        [showRequest doShow];
        isAddToDisplay = true;
    }
    if (isAddToDisplay) {
        [self.disPlayList addObject:showRequest];
        [self p_configFinishBlockForDisplayRequest:showRequest];
    }
        
}

- (BOOL)p_canResume:(id<IPopLayerRequest>)request
{
    ZYPopLayerRule *rule = [self findRuleOfPopLayerId:request.popLayerId];
    return rule.enableResume && request.interruptBlock && request.resumeBlock;
}

- (void)p_configFinishBlockForDisplayRequest:(id<IPopLayerRequest>)request
{
    if (!request) {
        return;
    }
    __weak typeof(request) weakRequest = request;
    __weak typeof(self) weakSelf = self;
    request.finishBlock = ^{
        if (weakRequest && weakSelf) {
            NSLog(@"PopLayer: displayRequest 【%@】 finish!", weakRequest.popLayerId);
            [weakSelf.disPlayList removeObject:weakRequest];
            [weakSelf p_showIfNeed];
        }
    };
}

@end
